{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "; ModuleID = \"\"\n",
      "target triple = \"unknown-unknown-unknown\"\n",
      "target datalayout = \"\"\n",
      "\n",
      "define fastcc i32 @\"fib_more\"(i32 %\".1\", i32 %\".2\", i32 %\".3\") \n",
      "{\n",
      "entry:\n",
      "  %\".7\" = alloca i32\n",
      "  %\".15\" = alloca i32\n",
      "  br label %\"main\"\n",
      "main:\n",
      "  %\".5\" = icmp sgt i32 %\".1\", 1\n",
      "  br i1 %\".5\", label %\"then\", label %\"else\"\n",
      "then:\n",
      "  %\".8\" = sub i32 %\".1\", 1\n",
      "  %\".9\" = add i32 %\".2\", %\".3\"\n",
      "  %\".10\" = call fastcc i32 @\"fib_more\"(i32 %\".8\", i32 %\".3\", i32 %\".9\")\n",
      "  store i32 %\".10\", i32* %\".7\"\n",
      "  br label %\"endif\"\n",
      "else:\n",
      "  %\".13\" = icmp eq i32 %\".1\", 1\n",
      "  br i1 %\".13\", label %\"then.1\", label %\"else.1\"\n",
      "endif:\n",
      "  %\".23\" = load i32, i32* %\".7\"\n",
      "  ret i32 %\".23\"\n",
      "then.1:\n",
      "  store i32 %\".3\", i32* %\".15\"\n",
      "  br label %\"endif.1\"\n",
      "else.1:\n",
      "  store i32 %\".2\", i32* %\".15\"\n",
      "  br label %\"endif.1\"\n",
      "endif.1:\n",
      "  %\".20\" = load i32, i32* %\".15\"\n",
      "  store i32 %\".20\", i32* %\".7\"\n",
      "  br label %\"endif\"\n",
      "}\n",
      "\n",
      "define fastcc i32 @\"fib\"(i32 %\".1\") \n",
      "{\n",
      "entry:\n",
      "  br label %\"main\"\n",
      "main:\n",
      "  %\".3\" = call fastcc i32 @\"fib_more\"(i32 %\".1\", i32 0, i32 1)\n",
      "  ret i32 %\".3\"\n",
      "}\n",
      "\n",
      "define i32 @\"entry_fib\"(i32 %\".1\") \n",
      "{\n",
      ".3:\n",
      "  %\".4\" = call fastcc i32 @\"fib\"(i32 %\".1\")\n",
      "  ret i32 %\".4\"\n",
      "}\n",
      "\n",
      "-----------------------------------optimized------------------------------------\n",
      "; ModuleID = '<string>'\n",
      "source_filename = \"<string>\"\n",
      "target triple = \"unknown-unknown-unknown\"\n",
      "\n",
      "; Function Attrs: nounwind readnone\n",
      "define fastcc i32 @fib_more(i32 %.1, i32 %.2, i32 %.3) local_unnamed_addr #0 {\n",
      "entry:\n",
      "  %.51 = icmp sgt i32 %.1, 1\n",
      "  br i1 %.51, label %then, label %else\n",
      "\n",
      "then:                                             ; preds = %entry, %then\n",
      "  %.3.tr4 = phi i32 [ %.9, %then ], [ %.3, %entry ]\n",
      "  %.2.tr3 = phi i32 [ %.3.tr4, %then ], [ %.2, %entry ]\n",
      "  %.1.tr2 = phi i32 [ %.8, %then ], [ %.1, %entry ]\n",
      "  %.8 = add nsw i32 %.1.tr2, -1\n",
      "  %.9 = add i32 %.3.tr4, %.2.tr3\n",
      "  %.5 = icmp sgt i32 %.8, 1\n",
      "  br i1 %.5, label %then, label %else.thread\n",
      "\n",
      "else:                                             ; preds = %entry\n",
      "  %.13 = icmp eq i32 %.1, 1\n",
      "  br i1 %.13, label %else.thread, label %0\n",
      "\n",
      "else.thread:                                      ; preds = %then, %else\n",
      "  %.3.tr.lcssa8 = phi i32 [ %.3, %else ], [ %.9, %then ]\n",
      "  br label %0\n",
      "\n",
      "; <label>:0:                                      ; preds = %else, %else.thread\n",
      "  %1 = phi i32 [ %.3.tr.lcssa8, %else.thread ], [ %.2, %else ]\n",
      "  ret i32 %1\n",
      "}\n",
      "\n",
      "; Function Attrs: nounwind readnone\n",
      "define fastcc i32 @fib(i32 %.1) local_unnamed_addr #0 {\n",
      "entry:\n",
      "  %.3 = tail call fastcc i32 @fib_more(i32 %.1, i32 0, i32 1)\n",
      "  ret i32 %.3\n",
      "}\n",
      "\n",
      "; Function Attrs: nounwind readnone\n",
      "define i32 @entry_fib(i32 %.1) local_unnamed_addr #0 {\n",
      ".3:\n",
      "  %.4 = tail call fastcc i32 @fib(i32 %.1)\n",
      "  ret i32 %.4\n",
      "}\n",
      "\n",
      "attributes #0 = { nounwind readnone }\n",
      "\n",
      "fib(0) = 0\n",
      "fib(1) = 1\n",
      "fib(2) = 1\n",
      "fib(3) = 2\n",
      "fib(4) = 3\n",
      "fib(5) = 5\n",
      "fib(6) = 8\n",
      "fib(7) = 13\n",
      "fib(8) = 21\n",
      "fib(9) = 34\n",
      "fib(10) = 55\n",
      "fib(11) = 89\n"
     ]
    },
    {
     "ename": "FileNotFoundError",
     "evalue": "[Errno 2] No such file or directory: 'd3dot_template.html'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mFileNotFoundError\u001b[0m                         Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-1-203ef783adf9>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m    315\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    316\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0m__name__\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m'__main__'\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 317\u001b[0;31m     \u001b[0mtest\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m<ipython-input-1-203ef783adf9>\u001b[0m in \u001b[0;36mtest\u001b[0;34m()\u001b[0m\n\u001b[1;32m    309\u001b[0m     \u001b[0mexecute\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mir_mod\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    310\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 311\u001b[0;31m     \u001b[0mrendered\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mgraphviz_render_revisions\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcontext\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_rm\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    312\u001b[0m     \u001b[0;32mwith\u001b[0m \u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'example_minilang.html'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'w'\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mfout\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    313\u001b[0m         \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrendered\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfile\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mfout\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/p/metadsl/explorations/kvbacker.py\u001b[0m in \u001b[0;36mgraphviz_render_revisions\u001b[0;34m(resmngr, since, backend, attrs)\u001b[0m\n\u001b[1;32m    489\u001b[0m         \u001b[0;34m'gv'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0m_graphviz_revs_backend\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    490\u001b[0m     }\n\u001b[0;32m--> 491\u001b[0;31m     \u001b[0;32mreturn\u001b[0m \u001b[0mbackends\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mbackend\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdots\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mattrs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    492\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    493\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/p/metadsl/explorations/kvbacker.py\u001b[0m in \u001b[0;36m_graphviz_d3_revs_backend\u001b[0;34m(dots)\u001b[0m\n\u001b[1;32m    514\u001b[0m     \"\"\"\n\u001b[1;32m    515\u001b[0m     \u001b[0;31m# See https://github.com/magjac/d3-graphviz\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 516\u001b[0;31m     \u001b[0;32mwith\u001b[0m \u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'd3dot_template.html'\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mfin\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    517\u001b[0m         \u001b[0mtemplate\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfin\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mread\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    518\u001b[0m     \u001b[0mjs_dots\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mmap\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mjson\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdumps\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmap\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;32mlambda\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msplitlines\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdots\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: 'd3dot_template.html'"
     ]
    }
   ],
   "source": [
    "\"\"\"\n",
    "Define a mini-language to compute the fibonnaci sequence.\n",
    "\n",
    "Uses LLVM for codegeneration.\n",
    "\"\"\"\n",
    "\n",
    "import inspect\n",
    "from llvmlite import ir\n",
    "from llvmlite import binding as llvm\n",
    "\n",
    "from kvbacker import (\n",
    "    ResourceManager,\n",
    "    Managed,\n",
    "    ManagedList,\n",
    "    graphviz_render_revisions,\n",
    ")\n",
    "\n",
    "\n",
    "class FunctionCollections(Managed):\n",
    "    pass\n",
    "\n",
    "\n",
    "class ContextResources(ResourceManager):\n",
    "    pass\n",
    "\n",
    "\n",
    "class Expr(Managed):\n",
    "    pass\n",
    "\n",
    "\n",
    "class FunctionDecl(Expr):\n",
    "    def init(self, name):\n",
    "        self.name = name\n",
    "\n",
    "    def __call__(self, *args):\n",
    "        args = self._resmngr.new(\n",
    "            ArgListVal,\n",
    "            [_fix_value(self._resmngr, x) for x in args],\n",
    "        )\n",
    "        return self._resmngr.new(CallVal, op=self, args=args)\n",
    "\n",
    "    def codegen(self, cgstate):\n",
    "        mod = cgstate.builder.module\n",
    "        return mod.get_global(self.name)\n",
    "\n",
    "\n",
    "class FunctionDefn(Expr):\n",
    "    def init(self, name, expr, arity):\n",
    "        self.name = name\n",
    "        self.expr = expr\n",
    "        self.arity = arity\n",
    "\n",
    "    def codegen_definition(self, ir_mod):\n",
    "        fn = self.codegen_declare(ir_mod)\n",
    "        fn.calling_convention = 'fastcc'\n",
    "        entry_block = fn.append_basic_block('entry')\n",
    "        main_block = fn.append_basic_block('main')\n",
    "        irbuilder = ir.IRBuilder()\n",
    "        cgstate = CodegenState(irbuilder, entry_block)\n",
    "        irbuilder.position_at_end(main_block)\n",
    "        value = self.expr.codegen(cgstate)\n",
    "        irbuilder.ret(value)\n",
    "        # Clean up\n",
    "        irbuilder.position_at_end(entry_block)\n",
    "        irbuilder.branch(main_block)\n",
    "\n",
    "    def codegen_declare(self, ir_mod):\n",
    "        try:\n",
    "            return ir_mod.get_global(self.name)\n",
    "        except KeyError:\n",
    "            argty = ir.IntType(32)\n",
    "            fnty = ir.FunctionType(argty, [argty] * self.arity)\n",
    "            fn = ir.Function(ir_mod, fnty, name=self.name)\n",
    "            return fn\n",
    "\n",
    "\n",
    "class ConstVal(Expr):\n",
    "    def init(self, value):\n",
    "        self.value = value\n",
    "\n",
    "    def codegen(self, cgstate):\n",
    "        intty = ir.IntType(32)\n",
    "        return intty(self.value)\n",
    "\n",
    "\n",
    "class ParamVal(Expr):\n",
    "    def init(self, name, pos):\n",
    "        self.name = name\n",
    "        self.pos = pos\n",
    "\n",
    "    def codegen(self, cgstate):\n",
    "        builder = cgstate.builder\n",
    "        fn = builder.function\n",
    "        arg = fn.args[self.pos]\n",
    "        return arg\n",
    "\n",
    "\n",
    "class CallVal(Expr):\n",
    "    def init(self, op, args):\n",
    "        self.op = op\n",
    "        self.args = args\n",
    "\n",
    "    def codegen(self, cgstate):\n",
    "        if isinstance(self.op, Expr):\n",
    "            assert isinstance(self.op, FunctionDecl)\n",
    "            callee = self.op.codegen(cgstate)\n",
    "            args = [a.codegen(cgstate) for a in self.args]\n",
    "            return cgstate.builder.call(callee, args)\n",
    "        else:\n",
    "            builder = cgstate.builder\n",
    "            assert len(self.args) == 2\n",
    "            lhs = self.args[0].codegen(cgstate)\n",
    "            rhs = self.args[1].codegen(cgstate)\n",
    "            if self.op == '+':\n",
    "                res = builder.add(lhs, rhs)\n",
    "            elif self.op == '-':\n",
    "                res = builder.sub(lhs, rhs)\n",
    "            elif self.op == '>':\n",
    "                res = builder.icmp_signed('>', lhs, rhs)\n",
    "            elif self.op == '==':\n",
    "                res = builder.icmp_signed('==', lhs, rhs)\n",
    "            else:\n",
    "                raise NotImplementedError(self.op)\n",
    "            return res\n",
    "\n",
    "\n",
    "class ArgListVal(ManagedList):\n",
    "    pass\n",
    "\n",
    "\n",
    "class IfElseVal(Expr):\n",
    "    def init(self, pred, then_expr, else_expr):\n",
    "        self.pred = pred\n",
    "        self.then_expr = then_expr\n",
    "        self.else_expr = else_expr\n",
    "\n",
    "    def codegen(self, cgstate):\n",
    "        builder = cgstate.builder\n",
    "        bb_then = builder.append_basic_block('then')\n",
    "        bb_else = builder.append_basic_block('else')\n",
    "        bb_after = builder.append_basic_block('endif')\n",
    "\n",
    "        pred = self.pred.codegen(cgstate)\n",
    "        builder.cbranch(pred, bb_then, bb_else)\n",
    "\n",
    "        builder.position_at_end(cgstate.entry_block)\n",
    "        phi = builder.alloca(ir.IntType(32))\n",
    "\n",
    "        builder.position_at_end(bb_then)\n",
    "        then_value = self.then_expr.codegen(cgstate)\n",
    "        builder.store(then_value, phi)\n",
    "        builder.branch(bb_after)\n",
    "\n",
    "        builder.position_at_end(bb_else)\n",
    "        else_value = self.else_expr.codegen(cgstate)\n",
    "        builder.store(else_value, phi)\n",
    "        builder.branch(bb_after)\n",
    "\n",
    "        builder.position_at_end(bb_after)\n",
    "        return builder.load(phi)\n",
    "\n",
    "\n",
    "class Context:\n",
    "    def __init__(self):\n",
    "        self._rm = ContextResources()\n",
    "        self._declfuncs = {}\n",
    "        self._definitions = {}\n",
    "\n",
    "    def define(self, fn):\n",
    "        fname = fn.__name__\n",
    "        fndecl = self._rm.new(FunctionDecl, name=fname)\n",
    "        self._declfuncs[fname] = {'decl': fndecl, 'defn': fn}\n",
    "        return fndecl\n",
    "\n",
    "    def visualize(self):\n",
    "        return self._rm.visualize()\n",
    "\n",
    "    def codegen(self):\n",
    "        ir_mod = ir.Module()\n",
    "        for k, defn in self._definitions.items():\n",
    "            defn.codegen_declare(ir_mod)\n",
    "        for k, defn in self._definitions.items():\n",
    "            defn.codegen_definition(ir_mod)\n",
    "        return ir_mod\n",
    "\n",
    "    def materialize(self):\n",
    "        while self._declfuncs:\n",
    "            name, info = self._declfuncs.popitem()\n",
    "            defn = info['defn']\n",
    "            defn = self._build_definition(name, defn)\n",
    "            self._definitions[name] = defn\n",
    "\n",
    "    def _build_definition(self, name, fn):\n",
    "        sig = inspect.signature(fn)\n",
    "        params = list(sig.parameters.items())\n",
    "        kwargs = {params[0][0]: self}\n",
    "        for i, (k, v) in enumerate(params[1:]):\n",
    "            kwargs[k] = self._rm.new(ParamVal, name=k, pos=i)\n",
    "        expr = fn(**kwargs)\n",
    "        defn = self._rm.new(\n",
    "            FunctionDefn, name=name, expr=expr, arity=len(params) - 1,\n",
    "        )\n",
    "        return defn\n",
    "\n",
    "    def call(self, op, args):\n",
    "        return self._rm.new(CallVal, op=op, args=self._arglist(*args))\n",
    "\n",
    "    def ifelse(self, pred, then_expr, else_expr):\n",
    "        return self._rm.new(\n",
    "            IfElseVal,\n",
    "            pred=pred,\n",
    "            then_expr=self._fix_value(then_expr),\n",
    "            else_expr=self._fix_value(else_expr),\n",
    "        )\n",
    "\n",
    "    def _arglist(self, *args):\n",
    "        return self._rm.new(\n",
    "            ArgListVal,\n",
    "            values=[self._fix_value(x) for x in args],\n",
    "        )\n",
    "\n",
    "    def _fix_value(self, val):\n",
    "        return _fix_value(self._rm, val)\n",
    "\n",
    "\n",
    "def _fix_value(rm, val):\n",
    "    if isinstance(val, Expr):\n",
    "        return val\n",
    "    else:\n",
    "        return rm.new(ConstVal, value=val)\n",
    "\n",
    "\n",
    "class CodegenState:\n",
    "    def __init__(self, ir_builder, entry_block):\n",
    "        self.builder = ir_builder\n",
    "        self.entry_block = entry_block\n",
    "\n",
    "\n",
    "def make_c_wrapper(fn_callee):\n",
    "    mod = fn_callee.module\n",
    "    fnty = fn_callee.function_type\n",
    "    fn = ir.Function(mod, fnty, name='entry_' + fn_callee.name)\n",
    "    builder = ir.IRBuilder(fn.append_basic_block())\n",
    "    builder.ret(builder.call(fn_callee, fn.args))\n",
    "\n",
    "\n",
    "def execute(ir_mod):\n",
    "    llvm.initialize()\n",
    "    llvm.initialize_native_target()\n",
    "    llvm.initialize_native_asmprinter()\n",
    "\n",
    "    llmod = llvm.parse_assembly(str(ir_mod))\n",
    "\n",
    "    print('optimized'.center(80, '-'))\n",
    "    pmb = llvm.create_pass_manager_builder()\n",
    "    pmb.opt_level = 1\n",
    "    pm = llvm.create_module_pass_manager()\n",
    "    pmb.populate(pm)\n",
    "    pm.run(llmod)\n",
    "    print(llmod)\n",
    "\n",
    "    target_machine = llvm.Target.from_default_triple().create_target_machine()\n",
    "\n",
    "    with llvm.create_mcjit_compiler(llmod, target_machine) as ee:\n",
    "        ee.finalize_object()\n",
    "        cfptr = ee.get_function_address(\"entry_fib\")\n",
    "\n",
    "        from ctypes import CFUNCTYPE, c_int\n",
    "\n",
    "        cfunc = CFUNCTYPE(c_int, c_int)(cfptr)\n",
    "\n",
    "        # TEST\n",
    "        for i in range(12):\n",
    "            res = cfunc(i)\n",
    "            print('fib({}) = {}'.format(i, res))\n",
    "\n",
    "        # Get CFG\n",
    "        ll_fib_more = llmod.get_function('fib_more')\n",
    "        cfg = llvm.get_function_cfg(ll_fib_more)\n",
    "        llvm.view_dot_graph(cfg, view=True)\n",
    "\n",
    "\n",
    "def test():\n",
    "    context = Context()\n",
    "\n",
    "    @context.define\n",
    "    def fib(ctx, n):\n",
    "        return fib_more(n, 0, 1)\n",
    "\n",
    "    @context.define\n",
    "    def fib_more(ctx, n, a, b):\n",
    "        pred_cont = ctx.call('>', [n, 1])\n",
    "        minus1 = ctx.call('-', [n, 1])\n",
    "        ab = ctx.call('+', [a, b])\n",
    "        added = fib_more(minus1, b, ab)\n",
    "\n",
    "        n_eq_1 = ctx.call('==', [n, 1])\n",
    "        return ctx.ifelse(pred_cont, added,\n",
    "                          ctx.ifelse(n_eq_1, b, a))\n",
    "\n",
    "    context.materialize()\n",
    "\n",
    "    ir_mod = context.codegen()\n",
    "    context.visualize().render(view=True)\n",
    "\n",
    "    make_c_wrapper(ir_mod.get_global('fib'))\n",
    "    print(ir_mod)\n",
    "\n",
    "    execute(ir_mod)\n",
    "\n",
    "    rendered = graphviz_render_revisions(context._rm)\n",
    "    with open('example_minilang.html', 'w') as fout:\n",
    "        print(rendered, file=fout)\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    test()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
